<template>
	<view class="review">
		<view class="head">
			<cover-image class="fanhui" src="/static/fanhui.png" @click="back"></cover-image>
			<text class="p" @click="back">预览</text>
		</view>
		<view class="content">
			<view class="address">
				<cover-image class="img" src="/static/positioning.png"></cover-image>
				<text class="text">{{ addressName }}</text>
			</view>
			<view v-if="options.code !== 'app_red_note'" class="one">
				第一步 点开图片长按保存
			</view>
			<view class="img-list">
				<cover-image class="img" v-for="item in imgs" :key="item" @click="previewImage(item)" :src="item"></cover-image>
			</view>
			<view v-if="options.code !== 'app_red_note'" class="one two">
				第二步 复制文案
				<view class="copy" :class="content && isContentDone ? '': 'disable'" @click="copyText">复制文本
				</view>
			</view>
			<view class="copywriting">
				<cover-image class="arrow" src="/static/jiantou.png"></cover-image>
				<view class="copywriting-content" :class="options.code === 'app_red_note' ? 'max': ''" ref="contentContainer">
					<up-skeleton v-show="!contentTitle && options.code === 'app_red_note'" style="margin-bottom: 20rpx;" rows="1"
						:title="false" rowsHeight="24" :loading="!contentTitle"></up-skeleton>
					<view v-show="options.code === 'app_red_note'" class="contentTitle">
						{{ contentTitle }}
					</view>
					<up-skeleton rows="3" :loading="!content">
					</up-skeleton>
					{{ content }}
					<text v-show="content && !isContentDone" class="dots">{{dots}}</text>
				</view>
			</view>
			<view v-if="options.code !== 'app_red_note'" class="one three">
				第三步 打开{{appName}}进行评论
			</view>
			<view class="button-list">
				<view class="button" :class="currentGenNum >= maxGenNum || !(content && isContentDone)? 'disable': ''"
					@click="getIndexInfo(true)">
					<view v-if="!isContentDone" class="loading-icon"></view>
					第
					{{currentGenNum}}/{{maxGenNum}} 条
				</view>
				<view class="button" :class="!(content && isContentDone)? 'disable': ''" @click="goToApp">打开{{appName}}评论</view>
			</view>
		</view>
		<view class="tips">
			若浏览器跳转{{appName}}失败,请手动打开{{appName}}
		</view>
	</view>
</template>

<script>
	import { channelListMap } from '../index/appList.js'

	export default {
		data() {
			return {
				options: {},
				addressName: '',
				appName: '',
				imgs: [],
				currentGenNum: 1,
				maxGenNum: 3,
				content: '',
				dots: '',
				contentTitle: '',
				isContentDone: false,
				lastLineCount: 0
			}
		},
		watch: {
			content: {
				handler() {
					this.$nextTick(() => {
						const container = this.$refs.contentContainer;
						if (container) {
							container.scrollTop = container.scrollHeight;
						}
					});
				},
				deep: true
			}
		},
		onLoad(options) {
			this.options = options
			this.getIndexInfo()
			this.donghua()
		},
		methods: {
			async getIndexInfo(isInit) {
				if ((this.currentGenNum >= this.maxGenNum || !(this.content && this.isContentDone)) && isInit) return
				this.contentTitle = ""
				this.content = ''
				this.addressName = this.options.addressName
				this.appName = channelListMap[this.options.code]
				const userNo = await this.getBrowserFingerprint()
				uni.request({
					url: '/app-api/market/ai/get',
					data: {
						storeCode: this.options.storeCode,
						channelId: this.options.channelId,
						no: isInit ? '' : (uni.getStorageSync('no') || ''),
						userNo
					},
					method: 'GET',
					success: (res) => {
						const data = res.data.data
						this.imgs = data.imageList
						this.currentGenNum = data.currentGenNum
						this.maxGenNum = data.maxGenNum
						uni.setStorageSync('no', data.genNo)
						if (data.messageText) {
							this.contentTitle = data.title
							this.characterByCharacterDisplay(data.messageText)
						} else {
							this.contentIofo()
						}
					}
				});
			},
			characterByCharacterDisplay(text) {
				this.isContentDone = false
				this.content = ''
				let currentIndex = 0
				const interval = 20 // 每个字符的显示间隔，单位毫秒

				const displayNextCharacter = () => {
					if (currentIndex < text.length) {
						this.content += text[currentIndex]
						currentIndex++
						// 计算当前行数并滚动
						this.$nextTick(() => {
							const container = this.$refs.contentContainer.$el || this.$refs.contentContainer;
							if (container) {
								const lineHeight = parseInt(window.getComputedStyle(container).lineHeight);
								const contentHeight = container.scrollHeight;
								const currentLineCount = Math.floor(contentHeight / lineHeight);

								if (currentLineCount !== this.lastLineCount) {
									this.lastLineCount = currentLineCount;
									container.scrollTop = container.scrollHeight;
								}
							}
						});
						setTimeout(displayNextCharacter, interval)
					} else {
						this.isContentDone = true
					}
				}

				displayNextCharacter()
			},
			getContentTitle() {
				uni.request({
					url: '/app-api/market/ai/chat/title',
					data: {
						no: uni.getStorageSync('no'),
						message: this.content
					},
					method: 'POST',
					success: (res) => {
						this.contentTitle = res.data?.data
					}
				});
			},
			contentIofo() {
				this.isContentDone = false
				const no = uni.getStorageSync('no')
				this.content = ""; // 当前展示的文本
				this.dots = ""; // 重置省略号

				fetch('/app-api/market/ai/chat/message', {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						'Accept': 'text/event-stream'
					},
					body: JSON.stringify({ no })
				}).then(response => {
					const reader = response.body.getReader();
					const decoder = new TextDecoder();
					const readStream = async () => {
						while (true) {
							const { done, value } = await reader.read();
							// 一旦流读取完成，启动逐字显示
							if (done) {
								this.isContentDone = true
								this.dots = ""; // 清除省略号
								if (this.options.code === 'app_red_note') { this.getContentTitle() }
								break;
							}
							const text = decoder.decode(value, { stream: true });
							// 以换行符拆分数据（SSE 数据是以 `\n\n` 结束）
							let lines = text.split("\n\n");
							// 处理完整的 SSE 消息
							for (let i = 0; i < lines.length - 1; i++) {
								let line = lines[i].trim();
								if (line.startsWith("data:")) {
									try {
										const jsonData = JSON.parse(line.slice(5)); // 去掉 `data: ` 解析 JSON
										this.content += jsonData.data.receive.content

										// 计算当前行数
										this.$nextTick(() => {
											const container = this.$refs.contentContainer.$el || this.$refs.contentContainer;
											if (container) {
												const lineHeight = parseInt(window.getComputedStyle(container).lineHeight);
												const contentHeight = container.scrollHeight;
												const currentLineCount = Math.floor(contentHeight / lineHeight);

												if (currentLineCount !== this.lastLineCount) {
													this.lastLineCount = currentLineCount;
													container.scrollTop = container.scrollHeight;
												}
											}
										});
									} catch (e) {
										console.error('JSON 解析错误:', e);
									}
								}
							}
						}
					};
					readStream();
				}).catch(error => {
					console.error('Request failed:', error);
				});
			},
			copyText() {
				if (!this.content || !this.isContentDone) return
				uni.setClipboardData({
					data: this.content, // 直接复制带 `\n` 的文本
					success: () => {
						uni.showToast({ title: '复制成功', icon: 'success' });
					},
					fail: () => {
						uni.showToast({ title: '复制失败', icon: 'error' });
					}
				});
			},
			back() {
				const code = uni.getStorageSync('urlCode')
				uni.navigateTo({ url: "/pages/index/index?code=" + code })
			},
			goToApp() {
				if (!this.content || !this.isContentDone) return
				if (this.options.code === 'app_red_note') {
					uni.request({
						url: '/app-api/market/channel/xhs/token',
						data: {},
						method: 'POST',
						success: (res) => {
							xhs.share({
								shareInfo: {
									type: 'normal', // 必填，笔记类型 'video' | 'normal'
									title: this.contentTitle, // 笔记标题
									content: this.content, // 笔记正文
									images: this.imgs, //图文类型必填，笔记图片，必须是服务器地址，暂时不支持本地文件
									video: '', // 视频类型必填，必须是服务器地址
									cover: '' // 视频封面图，必须是服务器地址，暂时不支持本地文件
								},
								verifyConfig: res.data.data,
								fail: (e) => {
									// 调用失败时执行的回调函数
									alert(e)
								}
							})
						}
					})
				} else {
					window.location.href = this.options.linkUrl;
				}
			},
			previewImage(current) {
				// let that = this
				uni.previewImage({
					indicator: true,
					loop: true,
					current: current,
					urls: this.imgs,
					longPressActions: {
						itemList: ['保存图片'],
						success(data) {
							// that.saveImage(imgurl)
						},
						fail: function(err) {
							console.log(err.errMsg);
						}
					}
				})
			},
			donghua() {
				let count = 0;
				setInterval(() => {
					count = (count + 1) % 4;
					this.dots = ".".repeat(count);
				}, 200);
			},
			async getBrowserFingerprint() {
				try {
					// 首先检查是否有缓存的指纹
					const cachedFingerprint = uni.getStorageSync('browserFingerprint');
					if (cachedFingerprint) {
						return cachedFingerprint;
					}

					// 收集浏览器特征
					const features = [
						navigator.userAgent || '',
						window.screen.width || '',
						window.screen.height || '',
						Intl.DateTimeFormat().resolvedOptions().timeZone || '',
						navigator.language || '',
						navigator.hardwareConcurrency || '',
						new Date().getTimezoneOffset() || '',
						window.devicePixelRatio || '',
						navigator.platform || ''
					].join('-');

					let fingerprint = '';

					// 尝试使用 crypto.subtle.digest
					if (window.crypto && window.crypto.subtle && window.crypto.subtle.digest) {
						try {
							const encoder = new TextEncoder();
							const data = encoder.encode(features);
							const hashBuffer = await crypto.subtle.digest('SHA-256', data);
							const hashArray = Array.from(new Uint8Array(hashBuffer));
							fingerprint = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
						} catch (error) {
							console.warn('Crypto API failed:', error);
						}
					}

					// 如果 crypto API 失败，使用简单的哈希函数
					if (!fingerprint) {
						let hash = 0;
						for (let i = 0; i < features.length; i++) {
							const char = features.charCodeAt(i);
							hash = ((hash << 5) - hash) + char;
							hash = hash & hash; // Convert to 32-bit integer
						}
						fingerprint = Math.abs(hash).toString(16).padStart(8, '0');
						
						// 添加随机字符串使其更独特
						const randomPart = Math.random().toString(36).substring(2);
						fingerprint += randomPart;
					}

					// 存储指纹以供后续使用
					uni.setStorageSync('browserFingerprint', fingerprint);
					return fingerprint;
				} catch (error) {
					console.warn('Fingerprint generation failed:', error);
					// 如果所有方法都失败，生成一个随机指纹
					const randomFingerprint = Date.now().toString(36) + Math.random().toString(36).substring(2);
					uni.setStorageSync('browserFingerprint', randomFingerprint);
					return randomFingerprint;
				}
			},
			getRandomSHA256Hex() {
				const SHA256Hex = uni.getStorageSync('SHA256Hex')
				if (SHA256Hex) return SHA256Hex
				const randomBytes = new Uint8Array(32); // 32 字节 = 256 位
				crypto.getRandomValues(randomBytes); // 生成随机字节
				const data = Array.from(randomBytes)
					.map(byte => byte.toString(16).padStart(2, '0'))
					.join('');
				uni.setStorageSync('SHA256Hex', data)
				return data
			}
		}
	}
</script>

<style>
	.review {
		position: absolute;
		top: 0;
		left: 0;
		bottom: 0;
		right: 0;
		background: linear-gradient(180deg, #C7D8FF 0%, #FFFFFF 42%, #F5F7F9 100%);

		.head {
			display: flex;
			height: 120rpx;
			align-items: center;
			padding-left: 40rpx;

			.fanhui {
				width: 20rpx;
				height: 40rpx;
				margin-right: 21rpx;
			}

			.p {
				font-size: 42rpx;
				color: #000;
				font-weight: bold;
			}
		}

		.content {
			width: 100%;
			background: #FFFFFF;
			box-shadow: 0rpx -6rpx 20rpx 0rpx rgba(0, 0, 0, 0.12);
			border-radius: 36rpx;
			margin-top: 10rpx;
			padding: 40rpx 25rpx;
			box-sizing: border-box;

			.address {
				background: linear-gradient(270deg, #FFFFFF 0%, #E2EBFF 100%);
				border-radius: 32rpx;
				height: 64rpx;
				display: flex;
				align-items: center;
				padding: 0 26rpx;
				margin-bottom: 30rpx;

				.img {
					width: 40rpx;
					height: 45rpx;
					margin-right: 12rpx;
				}

				.text {
					font-size: 28rpx;
					color: #333333;
				}
			}

			.one {
				color: #333333;
				font-size: 30rpx;
				text-indent: 10rpx;
				margin-bottom: 30rpx;
			}

			.img-list {
				width: 100%;
				display: flex;

				.img {
					width: calc((100% - 3 * 23rpx) / 4);
					aspect-ratio: 1 / 1;
					margin-right: 23rpx;
					border-radius: 10rpx;
				}

				.img:first-child {
					margin-left: 11.5rpx;
				}
			}

			.two {
				margin-top: 50rpx;
				position: relative;

				.copy {
					position: absolute;
					right: 0;
					top: -10rpx;
					background-color: #E3EBFF;
					color: #1F64FF;
					padding: 15rpx 20rpx 15rpx 15rpx;
					border-radius: 30rpx;
					cursor: pointer;
					font-size: 24rpx;
				}

				.disable {
					background-color: #f2f2f2;
					color: #b1b1b1;
				}
			}

			.copywriting {
				position: relative;
				margin-top: 30rpx;

				.arrow {
					width: 46rpx;
					height: 25rpx;
					position: relative;
					left: 60rpx;
				}
			}

			.copywriting-content {
				width: 100%;
				height: 300rpx;
				overflow: auto;
				border-radius: 30rpx;
				background: #F6F6F8;
				padding: 30rpx;
				box-sizing: border-box;
				white-space: pre-wrap;
				font-size: 26rpx;

				.dots {
					color: #8f8f8f;
					font-size: 26rpx;
					margin-left: 4rpx;
					animation: fadeInOut 1.5s infinite;
					display: inline-block;
					vertical-align: middle;
					line-height: 1.5;
					width: 60rpx;
					height: 42rpx;
					text-align: left;
					visibility: hidden;
				}

				.dots:not(:empty) {
					visibility: visible;
				}

				@keyframes fadeInOut {
					0% {
						opacity: 0.3;
					}

					50% {
						opacity: 1;
					}

					100% {
						opacity: 0.3;
					}
				}

				.contentTitle {
					font-size: 28rpx;
					font-weight: bold;
					color: #000;
					margin-bottom: 10rpx;
				}
			}

			.max {
				height: 570rpx;
			}

			.three {
				margin-top: 50rpx;
			}

			.button-list {
				width: 100%;
				display: flex;
				justify-content: space-around;
				margin-top: 60rpx;

				.button {
					width: calc((100% - 40rpx) / 2);
					height: calc((100% - 40rpx) / 2);
					background-color: #E3EBFF;
					color: #1F64FF;
					text-align: center;
					padding: 25rpx 0;
					border-radius: 45rpx;
					font-size: 28rpx;
					display: flex;
					align-items: center;
					justify-content: center;
					position: relative;

					.loading-icon {
						width: 40rpx;
						height: 40rpx;
						margin-right: 30rpx;
						position: relative;
						margin-left: -10rpx;
					}

					.loading-icon::before,
					.loading-icon::after {
						content: '';
						position: absolute;
						width: 100%;
						height: 100%;
						border-radius: 50%;
						background-color: currentColor;
						opacity: 0.6;
						animation: pulse 2s ease-in-out infinite;
					}

					.loading-icon::after {
						animation-delay: -1s;
					}
				}

				.disable {
					background-color: #f2f2f2;
					color: #b1b1b1;
				}
			}
		}

		.tips {
			font-weight: 400;
			font-size: 22rpx;
			color: #999999;
			text-align: left;
			margin: 40rpx;
			box-sizing: border-box;
		}
	}

	@keyframes pulse {
		0% {
			transform: scale(0);
			opacity: 0.6;
		}

		50% {
			transform: scale(1);
			opacity: 0.2;
		}

		100% {
			transform: scale(0);
			opacity: 0.6;
		}
	}
</style>